<?php
/**
 * Abstract model of an SQL server. Needs to be extended by a model providing its vendor-specific implementation.
 */
abstract class SQLServer {
	/**
	 * Data source in which your SQL server connection information is set.
	 * 
	 * @var DataSource $dataSource;
	 */
	protected $dataSource;
	
	/**
	 * Variable containing a PDO instance this class relies on.
	 * 
	 * @var PDO $connection
	 */
	protected $connection;
	
	/**
	 * Connects to a server.
	 * 
	 * @param DataSource $objDataSource
	 * @throws SQLServerException
	 * @return void
	 */
	public function connect($objDataSource) {
		// save datasource
		$this->dataSource = $objDataSource;
		
		// open connection
		try {
			$this->connection = new PDO($objDataSource->getDriverName().":host=".$objDataSource->getHostName(), $objDataSource->getUserName(), $objDataSource->getPassword(), $objDataSource->getDriverOptions());
		} catch(PDOException $e) {
			throw new SQLServerException($this->dataSource->getHostName(), $e->getMessage(), $e->getCode());
		}
	}
	
	/**
	 * Disconnects from server.
	 * 
	 * @return void
	 */
	public function disconnect() {
		$this->connection = null;
	}
	
	/**
	 * Executes a statement.
	 * 
	 * @param string $strQuery
	 * @throws SQLQueryExecutionException
	 * @return PDOStatement
	 */
	public function executeStatement($strQuery) {
		$stmt=null;
		try {
			$stmt = $this->connection->query($strQuery);
		} catch(PDOException $e) {
			throw new SQLQueryExecutionException($this->dataSource->getHostName(), $e->getMessage(), $e->getCode(), $strQuery);
		}
		return $stmt;
	}
	
	/**
	 * Executes a prepared statement.
	 * 
	 * @param	string	$strQuery
	 * @param	array	$tblBoundParameters
	 * 			This can be
	 * @throws	SQLQueryExecutionException
	 * @return	PDOStatement
	 */
	public function executePreparedStatement($strQuery, $tblBoundParameters=array()) {
		$stmt=null;
		try {
			$stmt = $this->connection->prepare($strQuery);
			if(sizeof($tblBoundParameters)) {
				// if array is multidimensional, execute each array contained in $tblBoundParameters 
				$blnIsMultiDimensionalArray = false;
				foreach($tblBoundParameters as $strKey => $mixValue) {
					if(is_array($mixValue)) {
						$stmt->execute($mixValue);
						$blnIsMultiDimensionalArray = true;
					}
				}
				
				// if array is not multidimensional, execute $tblBoundParameters directly
				if(!$blnIsMultiDimensionalArray) $stmt->execute($tblBoundParameters);
			} else {
				$stmt->execute();
			}
		} catch(PDOException $e) {
			throw new SQLQueryExecutionException($this->dataSource->getHostName(), $e->getMessage(), $e->getCode(), $strQuery);
		}
		return $stmt;
	}
	
	/**
	 * Gets rows affected by statement. Applies to SQL UPDATE, DELETE.
	 * 
	 * @param PDOStatement $stmt
	 * @return int
	 */
	public function getAffectedRows($stmt) {
		return $stmt->rowCount();
	}
	
	/**
	 * Returns the ID of the last inserted row. Applies to SQL INSERT, REPLACE
	 * 
	 * @return string
	 */
	public function getLastInsertId() {
		return $this->connection->lastInsertId();
	}
	
	/**
	 * Starts a transaction
	 */
	public function beginTransaction() {
		$this->connection->beginTransaction();
	}
	
	/**
	 * Commits transaction.
	 */
	public function commitTransaction() {
		$this->connection->commit();
	}
	
	/**
	 * Rolls back transaction.
	 */
	public function rollbackTransaction() {
		$this->connection->rollBack();
	}
	
	/**
	 * Gets the list of databases on server.
	 * 
	 * @return array(string)
	 */
	abstract public function getDatabases();
}